<script setup>
import useChannel from '@/store/channel'
import { getMessageList, getMentionMeList, markUnTopMessage } from '@/assets/api/message'
import { ElMessage } from 'element-plus'
import { getChannelMembers } from '@/assets/api/dialog-group'
import { handelMessageToString, useSendMessage } from '@/utils/dialog-utils'
import logo from '@/assets/image/logo.png'
import useEventBus from '@/use/use-event-bus.js'
import useFold from '@/store/fold'

const channelStore = useChannel()
const router = useRouter()
const route = useRoute()
const eventBus = useEventBus()
const postTextRef = ref()
const chatToolList = ref([
  { label: '收起', type: 'mini', svg: 'mini' },
  { label: '固定消息', type: 'message', svg: 'fixed-message' },
  { label: '收藏', type: 'collect', svg: 'collect' },
  { label: '设置', type: 'config', svg: 'config', auth: [1, 2, 3, 4, 5] },
])
const chatContentBodyRef = ref(null)

const guide = reactive({
  prev: false,
  prevId: null,
  next: false,
  nextId: null,
})

// 消息列队是否可以向上加载
const msgPrev = computed(() => {
  const { firstMessage } = channelStore.dialog
  const msgList = channelStore.currentDialogMsgList
  if (!firstMessage || !msgList.length) return false
  return firstMessage.id !== msgList[0].id
})

// 消息列队是否可以向下加载
const msgNext = computed(() => {
  const { lastMessage } = channelStore.dialog
  const msgList = channelStore.currentDialogMsgList
  if (!lastMessage || !msgList.length) return false
  return lastMessage.id !== msgList[msgList.length - 1].id
})

const topMsg = computed(() => {
  return channelStore.dialog.msgTops[0] || null
})

const loading = ref(false)
const foldStore = useFold()

function setTag(tag) {
  if (tag.type === 'mini') {
    foldStore.setHideChatContent(true)
  } else if (tag.type === 'message') {
    openChatPanel({
      name: 'PinMessage',
      props: {
        tag: 'file',
        channelId: channelStore.channelId,
      },
    })
  } else if (tag.type === 'collect') {
    openChatPanel({
      name: 'CollectMessage',
      props: {
        tag: 'file',
        channelId: channelStore.channelId,
      },
    })
  } else if (tag.type === 'config') {
    openChatPanel({ name: 'ChannelConfig', title: channelStore.dialog.type === 1 ? '聊天设置' : '群设置' })
  }
}

watch(
  [() => channelStore.dialog, () => route.query.jumpId],
  ([newDialog, jumpId], [oldDialog]) => {
    const channelId = newDialog?.id
    if (channelId) {
      if (newDialog.id === oldDialog?.id) {
        // 要跳转的消息ID
        if (jumpId) {
          handleJumpMsg(channelId, jumpId)
        }
      } else {
        eventBus.emit('closeChatPanel')
        getChatChannelMembersData(channelId)
        getMentionMeList({ channelId }).then((res) => {
          if (res.code === 200) {
            channelStore.setMentionMeMsgList(res.data)
          }
        })
        // 要跳转的消息ID
        if (jumpId) {
          handleJumpMsg(channelId, jumpId)
        } else if (newDialog.lastMessage) {
          const channelMsgMap = channelStore.channelMsgMap
          if (!channelMsgMap.has(channelId)) {
            getMessageListData(channelId, { msgIdBefore: newDialog.lastMessage.id })
          }
        } else {
          channelStore.addChannelMsgMap(channelId, [])
        }
      }
    }
  },
  {
    immediate: true,
  }
)
// 处理跳转消息
async function handleJumpMsg(channelId, jumpId) {
  const msgList = channelStore.channelMsgMap.get(channelId)
  if (msgList && msgList.some((i) => i.id === jumpId)) {
    nextTick(() => {
      chatContentBodyRef.value.jumpMessage(jumpId)
    })
  } else {
    await getMessageListData(channelId, { msgIdAfter: jumpId, jump: true })
  }
  setTimeout(() => {
    // 跳转后清空跳转id
    router.replace(`/chat?channelId=${channelId}`)
  }, 500)
}
function getMessageListData(
  channelId,
  { msgIdBefore = null, msgIdAfter = null, pageSize = 30, cover = true, jump = false, scrollBottomForce = true }
) {
  loading.value = true
  getMessageList({
    channelId,
    pageNum: 1,
    pageSize,
    msgIdBefore,
    msgIdAfter,
  }).then((res) => {
    loading.value = false
    if (res.code === 200) {
      if (msgIdBefore) {
        guide.prev = res.extData.hastNext
        guide.prevId = res.extData.nextId
      } else {
        guide.next = res.extData.hastNext
        guide.nextId = res.extData.nextId
      }
      if (cover) {
        channelStore.addChannelMsgMap(channelId, res.data)
      } else {
        const isPush = !!msgIdAfter
        isPush ? res.data.shift() : res.data.pop()
        channelStore.addChannelMsgList(res.data, isPush)
      }
      if (jump) {
        // 由于跳转时是向后查询,所以取 msgIdAfter
        chatContentBodyRef.value.jumpMessage(msgIdAfter)
      } else {
        chatContentBodyRef.value?.scrollBottom(scrollBottomForce)
      }
    } else {
      ElMessage.error(res.msg)
    }
  })
}
// 取消置顶
function unTopMessage() {
  markUnTopMessage(topMsg.value.id)
}
function handleLoadMore(direction) {
  if (loading.value) return
  const params = {
    pageSize: 31,
    cover: false,
    scrollBottomForce: false,
  }
  // 向上查找取第一条消息id
  if (msgPrev.value && direction === 'top') {
    params.msgIdBefore = channelStore.currentDialogMsgList[0]?.id
  }
  // 向下查找取最后一条消息id
  else if (msgNext.value && direction === 'bottom') {
    params.msgIdAfter = channelStore.currentDialogMsgList[channelStore.currentDialogMsgList.length - 1]?.id
  }
  if (params.msgIdBefore || params.msgIdAfter) {
    getMessageListData(channelStore.channelId, params)
  }
}

function handleLoadLatest() {
  router.replace({ name: 'Dialog', params: { channelId: route.query.channelId } })
  const { id, lastMessage } = channelStore.dialog
  getMessageListData(id, { msgIdBefore: lastMessage.id, scrollBottomForce: true })
}

function handleCanLoadMore(direction) {
  return direction === 'top' ? guide.prev : guide.next
}

function send(message) {
  useSendMessage(message, fileList.value)
    .then(() => {
      fileList.value = []
    })
    .catch(() => {
      fileList.value = []
    })
  chatContentBodyRef.value?.scrollBottom(true)
}

/**
 * 获取频道成员数据
 */
function getChatChannelMembersData(channelId) {
  getChannelMembers(channelId).then((res) => {
    if (res.code === 200) {
      channelStore.addMembersMap(channelId, res.rows)
    } else {
      ElMessage.error(res.msg)
    }
  })
}

const fileList = ref([])

function handleFilesChange(files) {
  fileList.value = files
}

const panelVisible = ref(false)
const panelRef = ref(null)

eventBus.on('openChatPanel', openChatPanel)
eventBus.on('closeChatPanel', closeChatPanel)

// 打开功能面板
function openChatPanel({ name, props, title, replace = false, stopClose = false }) {
  if (!stopClose && panelRef.value?.componentTitle === name) {
    closeChatPanel()
  } else {
    panelVisible.value = true
    nextTick(() => {
      panelRef.value.setComponent({
        name,
        props,
        title,
        replace,
      })
    })
  }
}
// 关闭功能面板
function closeChatPanel() {
  panelVisible.value = false
}

eventBus.on('cancelTagActive', () => {
  panelVisible.value = false
})
const userPostcardVisible = ref(false)
const userPostcardUserId = ref(null)
eventBus.on('openPostcard', openPostcard)
function openPostcard(userId) {
  if (userId) {
    userPostcardVisible.value = true
    userPostcardUserId.value = userId
  }
}
</script>

<template>
  <div class="chat-content" @click="panelVisible && closeChatPanel()">
    <template v-if="channelStore.dialog">
      <div class="chat-content-header">
        <img class="chat-icon" :src="channelStore.dialog.icon || logo" alt="频道头像" />
        <div class="chat-content-header-title">
          <div class="chat-title">
            <span>
              {{ channelStore.dialog.name }}
              <span v-if="channelStore.members?.length > 2">({{ channelStore.members.length }})</span>
            </span>
          </div>
        </div>
        <div class="chat-header-tool">
          <template v-for="(item, index) in chatToolList" :key="index">
            <el-tooltip
              v-if="!item.auth || item.auth.some((i) => i === channelStore.dialog.type)"
              :content="item.label"
              :show-arrow="false"
              :offset="6">
              <div class="tool-item" @click.stop="setTag(item)">
                <SvgIcon :name="`chat-${item.svg}`" color="var(--elp-color-info)" size="18"></SvgIcon>
              </div>
            </el-tooltip>
          </template>
        </div>
      </div>
      <!--对话消息区域-->
      <div class="chat-main">
        <!--置顶消息-->
        <div
          v-if="topMsg"
          class="top-message"
          @click="router.replace(`/chat?channelId=${channelStore.channelId}&jumpId=${topMsg.msgId}&type=message`)">
          <div class="top-message-content">
            <SvgIcon name="message-top" style="margin: 2px 5px 0 0" size="26"></SvgIcon>
            <div>
              <div class="top-message-text" v-html="handelMessageToString(topMsg.messageData)"></div>
              <div class="top-user">由&nbsp;{{ topMsg.createUser }}&nbsp;置顶</div>
            </div>
          </div>
          <el-tooltip content="取消置顶" placement="bottom">
            <SvgIcon name="close" size="16" @click.stop="unTopMessage"></SvgIcon>
          </el-tooltip>
        </div>
        <ChatContentBody
          ref="chatContentBodyRef"
          :key="channelStore.channelId"
          view-img
          :message-list="channelStore.currentDialogMsgList"
          :can-load-more="handleCanLoadMore"
          can-back-latest
          @loadMore="handleLoadMore"
          @loadLatest="handleLoadLatest"></ChatContentBody>
        <div class="chat-content-footer">
          <PostText
            ref="postTextRef"
            :key="channelStore.channelId"
            :disabled-mention-user="channelStore.dialog.type === 1"
            @send="send"
            @filesChange="handleFilesChange"></PostText>
        </div>
      </div>
    </template>
    <div class="channel-empty" v-else></div>
    <Transition name="channel-func-panel">
      <FunctionPanel v-show="panelVisible" ref="panelRef" @close="closeChatPanel"></FunctionPanel>
    </Transition>
    <UserPostcard v-model="userPostcardVisible" :user-id="userPostcardUserId"></UserPostcard>
  </div>
</template>

<style scoped lang="scss">
.chat-content {
  $header-height: 52px;

  @include use-flex(normal, normal, column);
  position: relative;
  height: 100%;
  width: 100%;
  padding: 16px 0;
  .chat-content-header {
    @include use-flex(center);
    position: absolute;
    height: $header-height;
    width: calc(100% - 12px);
    left: 0;
    top: 16px;
    padding: 0 14px;
    border-radius: var(--elp-border-radius-12);
    background: var(--chat-content-header-bg);
    backdrop-filter: blur(3px);
    overflow: hidden;
    z-index: 2;
    .chat-icon {
      height: 36px;
      width: 36px;
      border-radius: 50%;
    }
    .chat-content-header-title {
      padding-left: 11px;
      .chat-title {
        font-size: 18px;
        font-weight: bold;
      }
    }
    .chat-header-tool {
      @include use-flex(center);
      position: absolute;
      right: 14px;
      .tool-item {
        @include use-flex(center, center);
        height: 26px;
        width: 26px;
        cursor: pointer;
        border-radius: 4px;
        & + .tool-item {
          margin-left: 6px;
        }
        &:hover {
          background-color: var(--elp-color-info-light-7);
        }
      }
    }
  }
  .chat-main {
    @include use-flex(normal, normal, column);
    height: 100%;
    position: relative;
    .top-message {
      @include use-flex(center, space-between);
      position: absolute;
      top: calc($header-height + 5px);
      left: 10px;
      padding: 5px 10px;
      background: var(--elp-bg-color);
      width: calc(100% - 20px);
      border: 1px solid #d4d8e0;
      border-radius: 8px;
      z-index: 1;
      .top-message-content {
        @include use-flex(center);
        .top-message-text {
          cursor: pointer;
          @include clamp(2);
          font-size: 12px;
        }
      }
      .svg-icon:hover {
        cursor: pointer;
        background: rgba(212, 216, 224, 0.5);
      }
      .top-user {
        font-size: 12px;
        color: #666666;
      }
    }
    .chat-content-footer {
      width: 100%;
      padding: 0 28px 0 28px;
    }
    :deep(.chat-content-body) {
      padding-bottom: 10px;
      .chat-content-scroll {
        padding-top: $header-height;
      }
    }
  }
  .channel-empty {
    height: 100%;
    width: 100%;
    background-position: center;
    background-repeat: no-repeat;
  }
}
</style>
